<!DOCTYPE html><html class="appearance-auto" lang="zh-CN"><head><meta charset="UTF-8"><title>【Spring源码解析系列】 BeanDefinition</title><meta name="description" content="用创业者心态做好每一件事情！"><meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, initial-scale=1"><!-- Google Analytics --><!-- End Google Analytics -->
<!-- Baidu Analytics --><!-- End Baidu Analytics --><link rel="icon" href="/blog/images/favicon.png"><link rel="stylesheet" href="/blog/style/common/bulma.css"><link rel="stylesheet" href="/blog/style/base.css"><link rel="stylesheet" href="/blog/style/common/helper.css"><script src="/blog/js/common.js"></script><link rel="stylesheet" href="/blog/style/post.css"><link rel="stylesheet" href="/blog/style/themes/highlight-theme-light.css"><script src="/blog/js/highlight.pack.js"></script><meta name="description" content="
本文主要讲述Spring中BeanDefinition


定义BeanDefinition用于保存Bean相关信息，包括属性、构造方法函数、依赖的Bean名称及是否单例、延迟加载等。它是实例化Bean的原材料，String就是根据BeanDefinition中的信息实例化Bean。
详解BenDefinition是一个接口类，实现类以及子接口很多，如下：

BeanDefinition//BeanDefinition描述了一个bean实例，它有属性值，
//构造函数参数值，以及提供的进一步信息具体实现。
//这只是一个最小的接口:主要目的是允许一个和其他bean元数据。
public interface BeanDefinition extends AttributeAccessor, BeanMeta.."><!-- hexo injector head_end start -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-math@4.0.0/dist/style.css">
<!-- hexo injector head_end end --><meta name="generator" content="Hexo 5.4.1"><link rel="alternate" href="/blog/atom.xml" title="janedler's blog" type="application/atom+xml">
</head><body class="is-flex is-flex-direction-column"><header class="header-widget is-flex-shrink-0 is-hidden-mobile"><div class="container is-fullhd is-flex is-justify-content-space-between is-align-items-center is-full-height"><section class="is-hidden-mobile is-flex-shrink-0"><h2><a href="/blog/">田园牧歌(*︶*)'s blog</a></h2></section><h3 class="is-hidden-mobile is-family-serif is-full-height is-flex is-align-items-center is-flex-shrink-0"><div class="is-full-height" id="postTopic"><p class="is-full-height is-flex-shrink-0 is-flex is-align-items-center is-justify-content-center">【Spring源码解析系列】 BeanDefinition</p><p class="is-full-height is-flex-shrink-0 is-flex is-align-items-center is-justify-content-center">点击返回顶部</p></div></h3><aside class="is-flex-shrink-0"><h3 class="is-inline-block"><a href="/blog/">首页</a></h3><h3 class="is-inline-block"><a href="/blog/about">关于</a></h3><h3 class="is-inline-block"><a href="/blog/archives">归档</a></h3></aside></div></header><header class="is-flex header-widget is-flex-shrink-0 is-align-items-center is-justify-content-center is-hidden-tablet"><h3 class="is-inline-block"><a href="/blog/">首页</a></h3><h3 class="is-inline-block"><a href="/blog/about">关于</a></h3><h3 class="is-inline-block"><a href="/blog/archives">归档</a></h3></header><main><main class="container is-max-widescreen content section post-page pt-4 px-4"><div class="columns is-flex-desktop is-justify-content-center is-flex-direction-row-reverse"><div class="column is-3 is-hidden-mobile"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AE%9A%E4%B9%89"><span class="toc-text">定义</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%AF%A6%E8%A7%A3"><span class="toc-text">详解</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#BeanDefinition"><span class="toc-text">BeanDefinition</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#AnnotatedBeanDefinition"><span class="toc-text">AnnotatedBeanDefinition</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#AbstractBeanDefinition"><span class="toc-text">AbstractBeanDefinition</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#RootBeanDefinition"><span class="toc-text">RootBeanDefinition</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#ConfigurationClassBeanDefinition"><span class="toc-text">ConfigurationClassBeanDefinition</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ChildBeanDefinition"><span class="toc-text">ChildBeanDefinition</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#GenericBeanDefinition"><span class="toc-text">GenericBeanDefinition</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#AnnotatedGenericBeanDefinition"><span class="toc-text">AnnotatedGenericBeanDefinition</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#ScannedGenericBeanDefinition"><span class="toc-text">ScannedGenericBeanDefinition</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#BeanDefinition%E5%B8%B8%E8%A7%81%E7%9A%84%E8%AF%BB%E5%8F%96%E5%99%A8"><span class="toc-text">BeanDefinition常见的读取器</span></a></li></ol></li></ol></div><div class="column is-9"><header class="my-4"><a href="/blog/tags/Java"><i class="tag post-item-tag">Java</i></a><a href="/blog/tags/Spring"><i class="tag post-item-tag">Spring</i></a></header><h1 class="mt-0 mb-1 is-family-serif" id="postTitle">【Spring源码解析系列】 BeanDefinition</h1><time class="has-text-grey" datetime="2022-11-30T16:00:00.000Z">2022-12-01</time><article class="mt-2 post-content"><p><img src="https://janedler.oss-cn-beijing.aliyuncs.com/images/spring.png" alt="cover"></p>
<p>本文主要讲述Spring中BeanDefinition</p>
<span id="more"></span>

<h2 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h2><p>BeanDefinition用于保存Bean相关信息，包括属性、构造方法函数、依赖的Bean名称及是否单例、延迟加载等。它是实例化Bean的原材料，String就是根据BeanDefinition中的信息实例化Bean。</p>
<h2 id="详解"><a href="#详解" class="headerlink" title="详解"></a>详解</h2><p>BenDefinition是一个接口类，实现类以及子接口很多，如下：</p>
<p><img src="https://janedler.oss-cn-beijing.aliyuncs.com/images/202212011438071.png" alt="image-20221201143802953"></p>
<h3 id="BeanDefinition"><a href="#BeanDefinition" class="headerlink" title="BeanDefinition"></a>BeanDefinition</h3><pre><code class="java">//BeanDefinition描述了一个bean实例，它有属性值，
//构造函数参数值，以及提供的进一步信息具体实现。
//这只是一个最小的接口:主要目的是允许一个和其他bean元数据。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement &#123;

   //标准单例标识符
   String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
   //原型模式标识符
   String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
   //标识Bean的类别 0-用户定义的Bean
   int ROLE_APPLICATION = 0;
   //标识Bean的类别 1-来源于配置文件的Bean
   int ROLE_SUPPORT = 1;
   //标识Bean的类别 2-Spring内部的Bean
   int ROLE_INFRASTRUCTURE = 2;
   //设置父类名称
   void setParentName(@Nullable String parentName);
   //返回父类名称
   @Nullable
   String getParentName();
   //设置、返回 className
   void setBeanClassName(@Nullable String beanClassName);
   //设置、返回 className
   @Nullable
   String getBeanClassName();
   //设置、返回作用域
   void setScope(@Nullable String scope);
   @Nullable
   String getScope();
   //设置、返回 是否懒加载
   void setLazyInit(boolean lazyInit);
   boolean isLazyInit();
   //设置、返回当前Bean对象所依赖的其他Bean名称
   void setDependsOn(@Nullable String... dependsOn);
   @Nullable
   String[] getDependsOn();
   //设置、返回是否可以自动注入，对应@Autowired 注解
   void setAutowireCandidate(boolean autowireCandidate);
   boolean isAutowireCandidate();
   //设置、返回当前Bean 是否为主要候选Bean  一个接口多个实例对象，可以通过此属性来设置指定具体实例对象
   void setPrimary(boolean primary);
   //设置、返回当前Bean 是否为主要候选Bean  一个接口多个实例对象，可以通过此属性来设置指定具体实例对象
   boolean isPrimary();
   //设置、返回Bean的工厂类
   void setFactoryBeanName(@Nullable String factoryBeanName);
   @Nullable
   String getFactoryBeanName();
   //工厂方法
   void setFactoryMethodName(@Nullable String factoryMethodName);
   @Nullable
   String getFactoryMethodName();
   //返回构造参数值、属性值
   ConstructorArgumentValues getConstructorArgumentValues();
   default boolean hasConstructorArgumentValues() &#123;
      return !getConstructorArgumentValues().isEmpty();
   &#125;
   MutablePropertyValues getPropertyValues();
   default boolean hasPropertyValues() &#123;
      return !getPropertyValues().isEmpty();
   &#125;
   //初始化方法名称
   void setInitMethodName(@Nullable String initMethodName);
   @Nullable
   String getInitMethodName();
   //销毁方法的名称
   void setDestroyMethodName(@Nullable String destroyMethodName);
   @Nullable
   String getDestroyMethodName();
   //Bean的类别
   void setRole(int role);
   int getRole();

   void setDescription(@Nullable String description);

   @Nullable
   String getDescription();

   ResolvableType getResolvableType();

   boolean isSingleton();

   boolean isPrototype();

   boolean isAbstract();

   @Nullable
   String getResourceDescription();

   @Nullable
   BeanDefinition getOriginatingBeanDefinition();

&#125;
</code></pre>
<h3 id="AnnotatedBeanDefinition"><a href="#AnnotatedBeanDefinition" class="headerlink" title="AnnotatedBeanDefinition"></a>AnnotatedBeanDefinition</h3><p>AnnotatedBeanDefinition是Beanfinition子接口之一，该接口扩展了BeanDefinition的功能，其用来操作注解元数据。一般情况下，通过注解方式得到Bean(@Component、@Bean)</p>
<pre><code class="java">public interface AnnotatedBeanDefinition extends BeanDefinition &#123;

   // 获得当前 Bean 的注解元数据
   AnnotationMetadata getMetadata();

   // 获得当前 Bean 的工厂方法上的元数据
   @Nullable
   MethodMetadata getFactoryMethodMetadata();

&#125;
</code></pre>
<ul>
<li><p>AnnotationMetadata：主要对 Bean 的注解信息进行操作，如：获取当前 Bean 标注的所有注解、判断是否包含指定注解。</p>
</li>
<li><p>MethodMetadata：方法的元数据类。提供获取方法名称、此方法所属类的全类名、是否是抽象方法、判断是否是静态方法、判断是否是final方法等。</p>
</li>
</ul>
<h3 id="AbstractBeanDefinition"><a href="#AbstractBeanDefinition" class="headerlink" title="AbstractBeanDefinition"></a>AbstractBeanDefinition</h3><pre><code class="java">public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
      implements BeanDefinition, Cloneable &#123;

   // 默认的 SCOPE，默认是单例
   public static final String SCOPE_DEFAULT = &quot;&quot;;

   // 不进行自动装配
   public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;

   // 根据 Bean 的名字进行自动装配，byName
   public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;

   // 根据 Bean 的类型进行自动装配，byType
   public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;

   // 根据构造器进行自动装配
   public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;

   // 首先尝试按构造器自动装配。如果失败，再尝试使用 byType 进行自动装配。（Spring 3.0 之后已废除）
   @Deprecated
   public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;

   // 通过依赖检查来查看 Bean 的每个属性是否都设置完成  不检查
   public static final int DEPENDENCY_CHECK_NONE = 0;

   // 通过依赖检查来查看 Bean 的每个属性是否都设置完成  对依赖对象检查
   public static final int DEPENDENCY_CHECK_OBJECTS = 1;

   // 通过依赖检查来查看 Bean 的每个属性是否都设置完成  对基本类型，字符串和集合进行检查
   public static final int DEPENDENCY_CHECK_SIMPLE = 2;

   // 通过依赖检查来查看 Bean 的每个属性是否都设置完成  对全部属性进行检查
   public static final int DEPENDENCY_CHECK_ALL = 3;

   // 关闭应用上下文时需调用的方法名称
   public static final String INFER_METHOD = &quot;(inferred)&quot;;

   // 存放 Bean 的 Class 对象
   @Nullable
   private volatile Object beanClass;

   // Bean 的作用范围
   @Nullable
   private String scope = SCOPE_DEFAULT;

   // 非抽象
   private boolean abstractFlag = false;

   // 非延迟加载
   @Nullable
   private Boolean lazyInit;

   // 默认不自动装配
   private int autowireMode = AUTOWIRE_NO;

   // 默认不依赖检查
   private int dependencyCheck = DEPENDENCY_CHECK_NONE;

   // 依赖的 Bean 列表
   @Nullable
   private String[] dependsOn;

   // 可以作为自动装配的候选者，意味着可以自动装配到其他 Bean 的某个属性中
   private boolean autowireCandidate = true;

   private boolean primary = false;

   private final Map&lt;String, AutowireCandidateQualifier&gt; qualifiers = new LinkedHashMap&lt;&gt;();

   @Nullable
   private Supplier&lt;?&gt; instanceSupplier;

   private boolean nonPublicAccessAllowed = true;

   private boolean lenientConstructorResolution = true;

   // 创建当前 Bean 实例工厂类名称
   @Nullable
   private String factoryBeanName;

   // 创建当前 Bean 实例工厂类中方法名称
   @Nullable
   private String factoryMethodName;

   // 存储构造方法的参数
   @Nullable
   private ConstructorArgumentValues constructorArgumentValues;

   // 存储 Bean 属性名称以及对应的值
   @Nullable
   private MutablePropertyValues propertyValues;

   // 存储被覆盖的方法信息
   private MethodOverrides methodOverrides = new MethodOverrides();

   // init 方法名称
   @Nullable
   private String[] initMethodNames;

   // destroy 方法名称
   @Nullable
   private String[] destroyMethodNames;

   // 是否执行 init方法
   private boolean enforceInitMethod = true;

   // 是否执行 destroy 方法
   private boolean enforceDestroyMethod = true;

   // Bean 是否是用户定义的而不是应用程序本身定义的
   private boolean synthetic = false;

   // Bean 的身份类别，默认是用户定义的 Bean
   private int role = BeanDefinition.ROLE_APPLICATION;

   // Bean 的描述信息
   @Nullable
   private String description;

   // Bean 定义的资源
   @Nullable
   private Resource resource;
    
    ...省略...
&#125;
</code></pre>
<p>AbstractBeanDefinition 直接实现类：RootBeanDefinition、GenericBeanDefinition、ChildBeanDefinition</p>
<h4 id="RootBeanDefinition"><a href="#RootBeanDefinition" class="headerlink" title="RootBeanDefinition"></a>RootBeanDefinition</h4><p>该类继承自 AbstractBeanDefinition，它可以单独作为一个 BeanDefinition，也可以作为其他 BeanDefinition 的父类</p>
<pre><code class="java">public class RootBeanDefinition extends AbstractBeanDefinition &#123;

   // BeanDefinitionHolder 存储 Bean 的名称、别名、BeanDefinition
   @Nullable
   private BeanDefinitionHolder decoratedDefinition;

   // AnnotatedElement 是java反射包的接口，通过它可以查看 Bean 的注解信息
   @Nullable
   private AnnotatedElement qualifiedElement;

   /** Determines if the definition needs to be re-merged. */
   volatile boolean stale;

   // 允许缓存
   boolean allowCaching = true;

   // 工厂方法是否唯一
   boolean isFactoryMethodUnique;

   // 封装了 java.lang.reflect.Type，提供了泛型相关的操作
   @Nullable
   volatile ResolvableType targetType;

   /** Package-visible field for caching the determined Class of a given bean definition. */
   // 缓存 Class，表示 RootBeanDefinition 存储哪个类的信息
   @Nullable
   volatile Class&lt;?&gt; resolvedTargetType;

   /** Package-visible field for caching if the bean is a factory bean. */
   @Nullable
   volatile Boolean isFactoryBean;

   /** Package-visible field for caching the return type of a generically typed factory method. */
   // 缓存工厂方法的返回类型
   @Nullable
   volatile ResolvableType factoryMethodReturnType;

   /** Package-visible field for caching a unique factory method candidate for introspection. */
   @Nullable
   volatile Method factoryMethodToIntrospect;

   /** Package-visible field for caching a resolved destroy method name (also for inferred). */
   @Nullable
   volatile String resolvedDestroyMethodName;

   /** Common lock for the four constructor fields below. */
   // 这是以下四个构造方法字段的通用锁
   final Object constructorArgumentLock = new Object();

   /** Package-visible field for caching the resolved constructor or factory method. */
   // 用于缓存已解析的构造方法或工厂方法
   @Nullable
   Executable resolvedConstructorOrFactoryMethod;

   /** Package-visible field that marks the constructor arguments as resolved. */
   // 将构造方法参数标记为已解析
   boolean constructorArgumentsResolved = false;

   /** Package-visible field for caching fully resolved constructor arguments. */
   // 用于缓存完全解析的构造方法参数
   @Nullable
   Object[] resolvedConstructorArguments;

   /** Package-visible field for caching partly prepared constructor arguments. */
   // 缓存待解析的构造方法参数
   @Nullable
   Object[] preparedConstructorArguments;

   /** Common lock for the two post-processing fields below. */
   // 这是以下两个后处理字段的通用锁
   final Object postProcessingLock = new Object();

   /** Package-visible field that indicates MergedBeanDefinitionPostProcessor having been applied. */
   // 表明是否被 MergedBeanDefinitionPostProcessor 处理过
   boolean postProcessed = false;

   /** Package-visible field that indicates a before-instantiation post-processor having kicked in. */
   // 在生成代理的时候会使用，表明是否已经生成代理
   @Nullable
   volatile Boolean beforeInstantiationResolved;

   // 实际缓存的类型是 Constructor、Field、Method 类型
   @Nullable
   private Set&lt;Member&gt; externallyManagedConfigMembers;

   // InitializingBean中 的 init 回调函数名 afterPropertiesSet 会在这里记录，以便进行生命周期回调
   @Nullable
   private Set&lt;String&gt; externallyManagedInitMethods;

   // DisposableBean 的 destroy 回调函数名 destroy 会在这里记录，以便进生命周期回调
   @Nullable
   private Set&lt;String&gt; externallyManagedDestroyMethods;
&#125;
</code></pre>
<h5 id="ConfigurationClassBeanDefinition"><a href="#ConfigurationClassBeanDefinition" class="headerlink" title="ConfigurationClassBeanDefinition"></a>ConfigurationClassBeanDefinition</h5><p>该类继承自 RootBeanDefinition ，并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述在标注 <strong>@Configuration 注解的类</strong>中，通过 @Bean 注解实例化的 Bean。<br>其功能特点如下：<br>1、如果 @Bean 注解没有指定 Bean 的名字，默认会用方法的名字命名 Bean。<br>2、标注 @Configuration 注解的类会成为一个工厂类，而标注 @Bean 注解的方法会成为工厂方法，通过工厂方法实例化 Bean，而不是直接通过构造方法初始化。<br>3、标注 @Bean 注解的类会使用构造方法自动装配</p>
<h4 id="ChildBeanDefinition"><a href="#ChildBeanDefinition" class="headerlink" title="ChildBeanDefinition"></a>ChildBeanDefinition</h4><p>该类继承自 AbstractBeanDefinition。其相当于一个子类，不可以单独存在，必须依赖一个父 BeanDetintion，构造 ChildBeanDefinition 时，通过构造方法传入父 BeanDetintion 的名称或通过 setParentName 设置父名称。它可以从父类继承方法参数、属性值，并可以重写父类的方法，同时也可以增加新的属性或者方法。若重新定义 init 方法，destroy 方法或者静态工厂方法，ChildBeanDefinition 会重写父类的设置。</p>
<h4 id="GenericBeanDefinition"><a href="#GenericBeanDefinition" class="headerlink" title="GenericBeanDefinition"></a>GenericBeanDefinition</h4><p>GenericBeanDefinition 是 Spring 2.5 以后新引入的 BeanDefinition，是 ChildBeanDefinition 更好的替代者，它同样可以通过 setParentName 方法设置父 BeanDefinition。<br>最后三个 BeanDefinition 既实现了 AnnotatedBeanDefinition 接口，又间接继承 AbstractBeanDefinition 抽象类，这些 BeanDefinition 描述的都是注解形式的 Bean。</p>
<h5 id="AnnotatedGenericBeanDefinition"><a href="#AnnotatedGenericBeanDefinition" class="headerlink" title="AnnotatedGenericBeanDefinition"></a>AnnotatedGenericBeanDefinition</h5><p>该类继承自 GenericBeanDefinition ，并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述标注 <strong>@Configuration 注解的 Bean</strong>。</p>
<h5 id="ScannedGenericBeanDefinition"><a href="#ScannedGenericBeanDefinition" class="headerlink" title="ScannedGenericBeanDefinition"></a>ScannedGenericBeanDefinition</h5><p>该类继承自 GenericBeanDefinition ，并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述标注 <strong>@Component 注解的 Bean</strong>，其派生注解如 @Service、@Controller 也同理。</p>
<h3 id="BeanDefinition常见的读取器"><a href="#BeanDefinition常见的读取器" class="headerlink" title="BeanDefinition常见的读取器"></a>BeanDefinition常见的读取器</h3><p>AnnotatedBeanDefinitionReader：解析类上的注解，包含某些注解的时候（如：@Bean、@Component）会成为Bean。XmlBeanDefinitionReader：可以解析xml文件中的标签。<br>ClassPathBeanDefinitionScanner：扫描包路径的读取器。</p>
</article><section class="jump-container is-flex is-justify-content-space-between my-6"><!-- em is empty placeholder--><a class="button is-default" href="/blog/2022/12/01/Spring/Spring-AOP%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/" title="【Spring源码解析系列】 AOP源码解析"><i class="iconfont icon-prev mr-2 has-text-grey"></i><span class="has-text-weight-semibold">上一页: 【Spring源码解析系列】 AOP源码解析</span></a><a class="button is-default" href="/blog/2022/12/01/Spring/Spring-MVC/" title="【Spring源码解析系列】 SpringMVC"><span class="has-text-weight-semibold">下一页: 【Spring源码解析系列】 SpringMVC</span><i class="iconfont icon-next ml-2 has-text-grey"></i></a></section><article class="mt-6 comment-container"><script async repo="janedler/blog" src="https://utteranc.es/client.js" issue-term="pathname" theme="preferred-color-scheme"></script></article></div></div></main></main><footer class="is-flex is-flex-direction-column is-align-items-center is-flex-shrink-0 is-family-serif"><section class="sns-container"><!-- Github--><a title="github" target="_blank" rel="noopener nofollow" href="//github.com//janedler"><i class="iconfont icon-github"></i></a><!-- Ins--><!-- RSS--><a title="rss" target="_blank" rel="noopener nofollow" href="/blog/atom.xml"><i class="iconfont icon-rss"></i></a><!-- 知乎--><!-- 领英--><!-- 脸书--></section><p><span>Copyright ©</span><span> 田园牧歌(*︶*) 2022</span></p><div class="is-flex is-justify-content-center is-flex-wrap-wrap"><p>Powered by Hexo &verbar;&nbsp;</p><p class="is-flex is-justify-content-center"><a title="Hexo theme author" target="_blank" rel="noopener" href="//github.com/haojen">Theme by Haojen&nbsp;</a></p><div style="margin-top: 2px"><a class="github-button" title="github-button" target="_blank" rel="noopener" href="https://github.com/haojen/hexo-theme-Claudia" data-color-scheme="no-preference: light; light: light; dark: dark;" data-show-count="true"></a></div></div><div><span></span></div></footer><script async defer src="https://buttons.github.io/buttons.js"></script><script src="/blog/js/post.js"></script></body></html>